define('framework/associate/GillionAssociateDirectiveConstructor', ['angular'], function (angular) {

    return function ($compile, $dataSourceManager, $parse, $timeout, $filter) {

        var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
            hasProp = {}.hasOwnProperty;
        var AssociateMulti;

        var associateTmpl = '<input type="text" class="form-text form-suggestbox" value=""  />' +
            '<div ng-show="tableShow" class="form-suggestbox-dropdown" style="display: inline-block">' +
            '<div class="form-suggestbox-pager">'+
            '<span>找到 {{totalRecord}} 条记录，{{totalRecord}}显示{{recordFrom}}到{{recordTo}}</span>'+
            '<button class="btn"  ng-click="page === 1 || associate.goPage(page -1)"><i class="fi fi-reverse"></i></button>'+
            '<button class="btn" ng-click="(page === totalPage || totalPage <= 1) || associate.goPage(page +1)"><i class="fi fi-forward"></i></button>'+
            '</div>' +
            '<table class="form-suggestbox-table">'+
            '<tr ng-transclude></tr>'+
            '<tr ng-click="rowClick(record,$index)" ng-repeat="record in dataSource">' +
            '<td ng-show="multi" ><div class="form-clickbox" ><i class="fi" ></i></div></td>' +
            '<td ng-repeat="th in columns">{{record[th]}}</td></tr>'+
            '</table></div>';

        function Associate($scope, $element, $attrs,ngModel) {
            var me = this;
            me.element = $element;
            me.attrs = $attrs;
            me.scope = $scope;
            me.ngModel = ngModel;
        }


        Associate.prototype.doFilters = function (record, columns, filterNames) {
            var i, len, col, filterToken,tokens;
            for (i = 0, len = columns.length; i < len-1; i++) {
                col = columns[i];
                filterToken = filterNames[i];

                if(col && filterToken && record[col]){
                    if(filterToken.indexOf('|') == -1){
                        record[col] = $filter(filterToken)(record[col]);
                    }else{
                        tokens = filterToken.split('|');
                        tokens.forEach(function(item){
                            record[col] = $filter(item)(record[col]);
                        })
                    }
                }
            }
        };
        /**
         * 跳页
         */
        Associate.prototype.goPage = function (page, callback) {
            var me = this,
                scope = me.scope;
            $dataSourceManager.dataSources[scope.sourceName].currentPage=page;
            //this.initDataSource(callback);
        };
        /**
         * rowData去重
         */
        Associate.prototype.dupRemoval= function(rowDatas){

            var result = [], hash = {},value;
            for (var i = 0, elem; (elem = rowDatas[i]) != null; i++) {
                value = this.scope.valuePropGetter(elem);
                if (!hash[value]) {
                    result.push(elem);
                    hash[value] = true;
                }
            }
            return result;
        };

        /**
         * 每次请求数据初始化
         * @param callback
         */
        Associate.prototype.initDataSource= function(callback){
            var me = this,
                scope = me.scope;
            scope.$on(scope.sourceName,function(context,dataSource){
                scope.totalRecord = dataSource.totalRecord;
                scope.recordFrom = (dataSource.currentPage-1)*dataSource.pageSize+1;
                if(dataSource.records){
                    scope.recordTo = scope.recordFrom+dataSource.records.length-1;
                }else{
                    scope.recordTo = scope.recordFrom;
                }

                scope.dataSource =  dataSource.records;
                if(scope.dataSource){
                    scope.dataSource.forEach(function(item){
                        me.doFilters(item,scope.columns,scope.filters);
                    });
                }
                scope.page = dataSource.currentPage;
                scope.totalPage = dataSource.totalPage;
                if(me.attrs.multi){
                    if(scope.unmatchRemove){
                        me.showSelected();
                    }else{
                        me.unmatchKeep();
                    }
                }else{
                    if(scope.dataSource && scope.dataSource.length==1){
                        var rowData = scope.dataSource[0];
                        if(scope.inputText.val()===me.getDisplay(rowData)){
                            me.rowClick(scope.dataSource[0]);
                        }else{
                            scope.$selectedRow = {};
                            scope.setModelValue('');
                        }
                    }
                }
                if(!scope.$root.$$phase){
                    scope.$apply();
                }

                if (angular.isFunction(callback)) {
                    callback.call(me);
                }
            });
            //$dataSourceManager.getDataSource(scope.sourceName).then(function(dataSource) {
            //
            //});
        }
        /**
         * 重新搜索
         */
        Associate.prototype.reSearch = function () {
            var me = this,
                scope = me.scope,
                params;
            if (me.reSearchTimer) {
                $timeout.cancel(me.reSearchTimer);
                me.reSearchTimer = undefined;
            }
            me.reSearchTimer = $timeout(function () {
                if (scope.$keyword === undefined && scope.inputText.val()==="") {
                    me.showView();
                    return;
                }else{
                    //请求关键词
                    if(me.attrs.multi){
                        scope.$keyword = me.showSelected().join(scope.valueSeparator);
                    }else{
                        scope.$keyword = scope.inputText.val();
                    }
                    //空字符串是否搜索
                    if(!scope.emptySearch && (!scope.$keyword || scope.$keyword==scope.valueSeparator)){
                        return;
                    }
                    params = angular.extend({}, $dataSourceManager.dataSources[scope.sourceName].params  || {});
                    if (scope.inputText.val()) {
                        scope.keywordPropertySetter(params, scope.$keyword);
                    }
                    //更新keyword参数 会重新刷新请求
                    $dataSourceManager.dataSources[scope.sourceName].params=params;
                    me.reSearchTimer = undefined;
                    me.showView();
                }
            }, scope.delayTime);

        };


        Associate.prototype.rowClick = function (rowData) {
            var me = this,
                ngModel = me.ngModel,
                scope = me.scope,
            element=me.element;
            scope.setModelValue(scope.valuePropGetter(rowData));
            scope.inputText.val(me.getDisplay(rowData));
            scope.$selectedRow = rowData;

            me.hideView();
        };

        Associate.prototype.getDisplay = function (rowData) {
            var value = $parse(this.scope.displayExpress)(rowData);
            value =!!value?value.toString().replace(/<[^>]+>/g, ""):'';
            return value;
        };

        Associate.prototype.hideView = function () {
            this.scope.tableShow = false;
        };

        Associate.prototype.showView = function () {
            this.scope.tableShow = true;
        };

        Associate.prototype.showSelected = function(){
            var me = this,
                scope = me.scope;
            if(scope.dataSource && scope.dataSource.length==1){
                var rowData = scope.dataSource[0];
                if(scope.inputText.val()===me.getDisplay(rowData)){
                    me.rowClick(scope.dataSource[0]);
                }else{
                    scope.$selectedRow = {};
                    scope.setModelValue('');
                }
            }
        }
        /**
         * 未匹配的保留处理
         */
        Associate.prototype.unmatchKeep = function(){
            var scope = this.scope;
            scope.setModelValue(scope.inputText.val());
        }

        Associate.prototype.selectedRowToDisplay = function(){
            var me = this,
                scope = me.scope;
            scope.inputText.val(me.getDisplay(scope.$selectedRow));
        }

        Associate.prototype.selectedRowToModelValue = function(){
            var me = this,
                scope = me.scope;

            scope.setModelValue(scope.valuePropGetter(scope.$selectedRow));
        }

        Associate.prototype.keywordSelected = function(){

        }

        AssociateMulti = (function (superClass) {
            extend(AssociateMulti, superClass);
            function AssociateMulti($scope, $element, $attrs,ngModel){
                this.scope = $scope;
                this.attrs = $attrs;
                this.element = $element;
                this.ngModel = ngModel;
                AssociateMulti.__super__.constructor.call(this, this.scope,this.element,this.attrs,this.ngModel);
            }

            AssociateMulti.prototype.rowClick = function (rowData,index) {

                var displayArray = [],
                    submitArray = [],
                    me = this,
                    myScope = me.scope,
                length = myScope.dataSource.length;
                myScope.selected[index]=!myScope.selected[index];
                var checkbox = me.element.find("div.form-clickbox:eq("+index+")");
                myScope.isOperSelf = true;
                //已选中的处理
                if(myScope.selected[index]){
                    checkbox.attr("selected","selected");
                    myScope.$selectedRow.push(rowData);
                }else{
                    checkbox.removeAttr("selected");
                    var selectLength = myScope.$selectedRow.length;
                    for(var i=0;i<selectLength;i++){
                        var each = myScope.$selectedRow[i];
                        if(myScope.valuePropGetter(rowData)===myScope.valuePropGetter(each)){
                            myScope.$selectedRow.splice(i,1);
                            break;
                        }
                    }
                }
                var selectLength = myScope.$selectedRow.length;
                for(var i=0;i<selectLength;i++){
                    var each = myScope.$selectedRow[i];
                    submitArray.push(myScope.valuePropGetter(each));
                    displayArray.push(me.getDisplay(each));
                }
                myScope.setModelValue(submitArray.join(myScope.valueSeparator));
                myScope.inputText.val(displayArray.join(myScope.valueSeparator));
            };

            /**根据输入框显示勾选和更改selectedRow 并返回未匹配的key数组*/
            AssociateMulti.prototype.showSelected = function(){
                var me = this;
                var selectedArr = me.keywordSelected();
                var missKeyArr = me.keywordSelectedRow(selectedArr);
                me.selectedRowToModelValue();
                if(missKeyArr.length>0 && me.scope.unmatchRemove){
                    //如果仍有未选中的 则只显示出最后一个未选中的
                    me.selectedRowToDisplay(missKeyArr[missKeyArr.length-1]);
                }
                return missKeyArr;
            };
            //根据输入框内容 更改显示checkbox 并返回已选的行数组
            AssociateMulti.prototype.keywordSelected = function(){
                var me = this,
                    scope = me.scope,
                    index = 0,
                    inputVal = scope.inputText.val(),
                    selectedArr=[];
                if(inputVal) {
                    var keywordArr = inputVal.split(scope.valueSeparator);
                    if(!scope.deleteOperate){
                        //非删除的时候 最后一个不勾选
                        keywordArr = keywordArr.splice(0,keywordArr.length-1);
                    }
                    //勾选checkbox
                    if(scope.dataSource){
                        scope.dataSource.forEach(function (each) {
                            if (keywordArr.filter(function (item) {
                                    return me.getDisplay(each) == item;
                                }).length == 1) {
                                scope.selected[index] = true;
                                selectedArr.push(each);
                            } else {
                                scope.selected[index] = false;
                            }
                            index++;
                        });
                    }

                }else{
                    if(scope.dataSource){
                        scope.dataSource.forEach(function (each) {
                            scope.selected[index] = false;
                            index++;
                        });
                    }
                }
                return selectedArr;
            }

            //根据输入框内容 和已选数组 重新构造 selectedRow 并返回未匹配的key数组
            AssociateMulti.prototype.keywordSelectedRow = function(selectedArr){
                var me = this,
                    scope = me.scope,
                    missKeyArr = [],
                    inputVal = scope.inputText.val();
                if(inputVal){
                    if(angular.isArray(selectedArr)){
                        selectedArr.forEach(function(each){
                            scope.$selectedRow.push(each);
                        })
                    }
                    var arr = [],
                        keywordArr = inputVal.split(scope.valueSeparator);

                    keywordArr.forEach(function(each){
                        if(scope.$selectedRow.filter(function(item){
                                if(me.getDisplay(item)==each){
                                    arr.push(item);
                                    return true;
                                }
                                return false;}).length>0){
                        }else{
                            missKeyArr.push(each);
                        }
                    });
                    scope.$selectedRow = me.dupRemoval(arr);
                }else{
                    scope.$selectedRow = [];
                }
                return missKeyArr;
            };

            AssociateMulti.prototype.selectedRowToModelValue = function(val){
                var me = this,
                    scope = me.scope,
                    modelValue;
                var submitArray = [];

                scope.$selectedRow.forEach(function(each){
                    submitArray.push(scope.valuePropGetter(each));
                });
                if(val){
                    submitArray.push(val);
                }
                modelValue = submitArray.join(scope.valueSeparator);
                scope.setModelValue(modelValue);
                return modelValue;
            }

            AssociateMulti.prototype.selectedRowToDisplay = function(val){
                var me = this,
                    scope = me.scope,
                    lastChar='';
                var displayArray = [];

                scope.$selectedRow.forEach(function(each){
                    displayArray.push(me.getDisplay(each));
                });
                if(val){
                    displayArray.push(val);
                }
                if(scope.inputText.val().charAt(scope.inputText.val().length-1)===scope.valueSeparator){
                    lastChar = scope.valueSeparator;
                }
                scope.inputText.val(displayArray.join(scope.valueSeparator)+lastChar);
            }

            AssociateMulti.prototype.unmatchKeep = function(){
                var me = this,
                    textValue,
                    selectedArr = me.keywordSelected(),
                    missKeyArr = me.keywordSelectedRow(selectedArr),
                    scope = me.scope;
                var modelValue = me.selectedRowToModelValue();
                var displayArray = [];

                scope.$selectedRow.forEach(function(each){
                    displayArray.push(me.getDisplay(each));
                });
                if(missKeyArr.length>0){
                    textValue = scope.inputText.val();
                    if(textValue){
                        scope.inputText.val(displayArray.join(scope.valueSeparator) + scope.valueSeparator+ missKeyArr.join(scope.valueSeparator));
                        scope.setModelValue(modelValue + scope.valueSeparator+ missKeyArr.join(scope.valueSeparator));
                    }else{
                        scope.inputText.val(missKeyArr.join(scope.valueSeparator));
                        scope.setModelValue(missKeyArr.join(scope.valueSeparator));
                    }
                }
            }

            return AssociateMulti;
        })(Associate);
        return {
            restrict: 'E',
            template:associateTmpl,
            priority: 100,
            transclude:true,
            scope: {

                sourceName:'@',
                keywordProp: '@',
                multi:'@',

                displayExpress: '@',
                valueProp:'@',
                selectedRow: '='
            },
            require: '^?ngModel',
            controller:function($scope, $element, $attrs){
                $scope.columns = $scope.columns || [];
                $scope.filters = $scope.filters || [];
                function myControllter(col){
                    this.addColumn=function(col){
                        $scope.columns.push(col);
                    };
                    this.addFilterName=function(filterName){
                        $scope.filters.push(filterName);
                    }
                };
                return new myControllter();
            },
            compile:function (tElement, tAttrs) {
                //tElement.find("input").attr('ng-change','associate.reSearch()');
                return function (scope, element, attrs, ngModel) {

                    var keywordProperty = scope.keywordProp || scope.displayExpress ||'keyword',
                        totalCountProperty = scope.totalCountProp || 'totalCount',
                        valueProp = scope.valueProp || scope.displayExpress || 'id',
                        timer;
                    scope.valueSeparator = attrs.valueSeparator || ',';
                    scope.$selectedRow = scope.selectedRow || [];
                    scope.emptySearch = attrs.emptySearch=="true" || false;
                    scope.unmatchRemove = attrs.unmatchRemove=="true" || false;//不匹配的是否自动删除
                    scope.deleteOperate = false;//是否删除操作
                    scope.delayTime = attrs.delayTime || 300;
                    scope.columns = scope.columns || [];
                    scope.filters = scope.filters || [];
                    scope.inputText = element.find("input");
                    scope.tableShow = false;
                    scope.isOperSelf = false;//判断是否是自己在操作 用于更改数组时判断是否更新视图
                    scope.selected = [];
                    // default properties
                    scope.page = 1;
                    scope.pageSize = Number(attrs.pageSize) || 10;
                    // settergi
                    scope.keywordPropertySetter = $parse(keywordProperty).assign;
                    // getter
                    scope.totalCountGetter = $parse(totalCountProperty);
                    scope.valuePropGetter = $parse(valueProp);

                    scope.associate =
                        scope.multi? new AssociateMulti(scope, element, attrs,ngModel):new Associate(scope, element, attrs,ngModel);
                    var associate = scope.associate;
                        scope.rowClick = function(val,index){
                        associate.rowClick(val,index);
                    }

                    if(attrs.multi){
                        element.find("table tr:first-child").prepend( '<th></th>');
                    }

                    //双向绑定
                    if (angular.isString(attrs.selectedRow)) {
                        if(angular.isArray(scope.selectedRow)){
                            scope.$watch("$selectedRow",function(val){
                                scope.selectedRow = scope.$selectedRow;
                            });
                            scope.$watchCollection("selectedRow",function(val){
                                scope.$selectedRow = val;
                                if(!scope.isOperSelf){
                                    associate.selectedRowToDisplay();
                                    associate.keywordSelected();
                                    associate.selectedRowToModelValue();
                                }
                            });
                        }else{
                            scope.$watch("$selectedRow",function(val){
                                scope.selectedRow = val;
                            }) ;
                            scope.$watch('selectedRow',function(val){
                                scope.$selectedRow = val;
                                if(!scope.isOperSelf){
                                    associate.selectedRowToDisplay();
                                    associate.keywordSelected();
                                    associate.selectedRowToModelValue();
                                }
                            })
                        }
                    }
                    if (attrs.width) {
                        scope.inputText.css("width", attrs.width);
                    }else{
                        scope.inputText.css("width", "200px");
                    }

                    scope.setModelValue = function(val){
                        if(ngModel) {
                            ngModel.$setViewValue(val);
                        }
                    };
                    //初显示回选值
                    if(scope.$selectedRow){
                        associate.selectedRowToDisplay();
                        associate.keywordSelected();
                        associate.selectedRowToModelValue();
                    }

                    if(ngModel){
                        ngModel.$formatters.push(function(value){
                            ngModel.$setViewValue(value);
                        });
                    }

                    scope.inputText.on("blur", function (event) {
                        timer = $timeout(function () {
                            if(scope.unmatchRemove){
                                scope.deleteOperate=true;//离开同删除操作 最后一个得判断
                                associate.showSelected();
                                associate.selectedRowToDisplay();
                                scope.isOperSelf = false;
                            }else{
                                associate.unmatchKeep();
                            }
                            associate.hideView();
                            scope.$apply();
                        }, 200);
                    });

                    $(document).on('click', function (event) {
                        if (timer) {
                            $timeout.cancel(timer);
                        }

                        if (element.find(event.srcElement || event.target).length === 0 && scope.tableShow) {
                            if(scope.unmatchRemove){
                                scope.deleteOperate=true;//离开同删除操作 最后一个得判断
                                associate.showSelected();
                                associate.selectedRowToDisplay();
                                scope.isOperSelf = false;
                            }else{
                                associate.unmatchKeep();
                            }
                            associate.hideView();
                            scope.$apply();
                        }
                    });
                    scope.inputText.on('focus', function (event) {
                        associate.showView();
                        scope.$digest();
                    });
                    scope.currIndex =  scope.currIndex || -1;
                    associate.initDataSource();
                    scope.inputText.on('keydown', function (event) {
                        var e = e || event,
                            currKey = e.keyCode || e.which || e.charCode,
                            trs = element.find("tbody tr[ng-click]"),
                            keyLength = trs.length-1;
                        scope.isOperSelf = true;
                        switch (currKey) {
                            //方向左键
                            case 37:
                                if (1 < scope.page) {
                                    scope.$apply(function(){
                                        associate.goPage(scope.page - 1);
                                    })
                                }
                                return false;
                                break;
                            //方向右键
                            case 39:
                                var tempPage = scope.page + 1 > scope.totalPage ? 1 : scope.page + 1;
                                scope.$apply(function(){
                                    associate.goPage(tempPage);
                                })
                                return false;
                                break;
                            //方向上键
                            case 38:
                                trs.removeClass("current");
                                scope.currIndex -=1;
                                trs.eq([(scope.currIndex+keyLength)%keyLength]).addClass("current");
                                break;
                            //方向下键
                            case 40:
                                trs.removeClass("current");
                                scope.currIndex +=1;
                                trs.eq((scope.currIndex+keyLength)%keyLength).addClass("current");
                                break;
                            //空格键
                            case 32:
                                trs[scope.currIndex].click();
                                return false;
                                break;
                            //回车键
                            case 13:
                                break;
                            default :
                                currKey==8?scope.deleteOperate=true:scope.deleteOperate=false;
                                associate.reSearch();
                                break;
                        }
                    });
                }
            }
        };
    };
});